package org.sixtynine.stock.service.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.sixtynine.stock.Constants;
import org.sixtynine.stock.ReturnData;
import org.sixtynine.stock.entity.BaseEntity;
import org.sixtynine.stock.entity.Company;
import org.sixtynine.stock.entity.DailyShareData;
import org.sixtynine.stock.service.GenericService;
import org.sixtynine.stock.service.business.StockUtil;
import org.sixtynine.stock.util.DateUtil;
import org.sixtynine.stock.util.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component(ExcelProcessorFactory.FILE_TYPE_COMPANY_DAILY_SHARE_DATA_LIST)
public class CompanyDailyShareListProcessor extends CompanyDataListProcessor {

	Date formatedDate;

	@Autowired
	GenericService genericService;

	private static Map<String, DailyShareData> exsistingDataMap;
	private static Map<String, DailyShareData> exsistingCompanyDataMap;

	private static void processExsistingRecords(List<BaseEntity> dataList) {
		exsistingDataMap = new HashMap<String, DailyShareData>();
		exsistingCompanyDataMap = new HashMap<String, DailyShareData>();

		for (BaseEntity baseEntity : dataList) {
			DailyShareData dailyShareData = (DailyShareData) baseEntity;
			exsistingDataMap.put(
					DateUtil.getDataString(dailyShareData.getDate()),
					dailyShareData);

			exsistingCompanyDataMap.put(dailyShareData.getCompany().getCode(),
					dailyShareData);
		}
	}

	public static Map<String, String> methodMap = new HashMap<String, String>();

	@Override
	public void init() {
		methodMap.put("SHARE_VOLUME", "setVolume");
		methodMap.put("TRADE_VOLUM", "setNoOfTrade");
		methodMap.put("TURNOVER", "setTurnOver");
		methodMap.put("HIGH", "setHigh");
		methodMap.put("LOW", "setLow");
		methodMap.put("OPEN", "setOpeningPrice");
		methodMap.put("CLOSE", "setSharePrice");
		super.init();
	}

	@Override
	public ReturnData<List<? extends BaseEntity>> process(String filePath) {

		ReturnData<List<? extends BaseEntity>> returnData = new ReturnData<List<? extends BaseEntity>>(
				Constants.SUCCESS, "");

		init();

		FileInputStream fis = null;

		try {
			List<BaseEntity> dailyShareDataList = new ArrayList<BaseEntity>();
			File file = new File(filePath);

			fis = new FileInputStream(file);
			// Get the workbook instance for XLS file
			Workbook workbook = WorkbookFactory.create(fis);

			// Get first sheet from the workbook
			Sheet sheet = workbook.getSheetAt(0);

			// Get iterator to all the rows in current sheet
			Iterator<Row> rowIterator = sheet.iterator();
			int rowIndex = 0;

			String fileName = file.getName();
			String companyCode = fileName.split("_")[0];

			if (!StockUtil.getFileName(fileName).equals(
					Constants.DAILY_SHARE_DATA)) {
				returnData.setNo(Constants.ERROR);
				returnData.setMsg("Please add daily share data only");
				return returnData;
			}

			Company company = companyMap.get(companyCode);
			if (company == null) {
				returnData.setNo(Constants.ERROR);
				returnData.setMsg("Company code " + companyCode
						+ " not found in the database, wrong file name format");
			}

			Criterion criterion = (Restrictions.eq("company.id",
					company.getId()));
			List<BaseEntity> dataList = genericService.findByCriteria(
					criterion, DailyShareData.class);
			if (dataList.size() > 0) {
				processExsistingRecords(dataList);
			}

			List<String> headerNames = new ArrayList<String>();
			while (rowIterator.hasNext()) {

				// check whether the record is already exist

				Row row = rowIterator.next();
				// Get iterator to all cells of current row
				Iterator<Cell> cellIterator = row.cellIterator();

				if (rowIndex == 0) {
					Cell firstCell = row.getCell(0);
					if (firstCell == null) {
						returnData.setNo(Constants.ERROR);
						returnData
								.setMsg("Error file format, data should be started from first row and column");
						return returnData;
					}
					rowIndex++;

					int colIndex = 0;
					while (cellIterator.hasNext()) {

						Cell cell = cellIterator.next();
						String cellVal = (String) getCellValue(cell);

						if (colIndex > 0 && !StringUtils.isEmpty(cell)) {
							headerNames.add(cellVal);
						}

						colIndex++;
					}

					continue;
				}

				int colIndex = 0;
				DailyShareData dailyShareData = null;
				while (cellIterator.hasNext()) {
					Cell cell = cellIterator.next();
					Object cellVal = getCellValue(cell);

					if (StringUtils.isEmpty(cellVal)) {
						colIndex++;
						continue;
					}

					// for the numeric values, set the empty ones as zero
					if (cellVal == null && colIndex > 0) {
						cellVal = 0.0;
					}

					if (colIndex == 0) {
						Date date = cell.getDateCellValue();
						// check future date
						if (DateUtil.checkFutureDate(date)) {
							returnData.setNo(Constants.ERROR);
							returnData.setMsg("Please enter corrcet date "
									+ date);
							return returnData;
						}
						String dateCode = DateUtil.getDataString(date);
						if (exsistingDataMap != null
								&& exsistingCompanyDataMap
										.containsKey(companyCode)) {
							if (exsistingDataMap.containsKey(dateCode)) {
								dailyShareData = exsistingDataMap.get(dateCode);
							} else {
								dailyShareData = new DailyShareData();
							}

						} else {
							dailyShareData = new DailyShareData();
						}

						dailyShareData.setDate(date);
						dailyShareData.setCompany(company);

					} else {
						String header = headerNames.get(colIndex - 1);
						String setter = methodMap.get(header);

						cellVal = (Double) getCellValue(cell);

						Method method = dailyShareData.getClass().getMethod(
								setter, double.class);
						method.invoke(dailyShareData, cellVal);
					}

					colIndex++;
				}

				if (dailyShareData != null) {
					dailyShareDataList.add(dailyShareData);
				}
				rowIndex++;
			}

			returnData.setData(dailyShareDataList);

		} catch (IOException e) {
			e.printStackTrace();
			returnData.setNo(Constants.ERROR);
			returnData.setMsg(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			returnData.setNo(Constants.ERROR);
			returnData.setMsg(e.getMessage());
		} finally {
			FileUtil.close(fis);
		}

		return returnData;
	}

}
